﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Visualization.DataModel;
using System.ComponentModel;
using Microsoft.Windows.Controls;
using Microsoft.Research.DynamicDataDisplay;
using Microsoft.Research.DynamicDataDisplay.DataSources;

namespace Visualization
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class DisagreementGraph : Window
    {
        IEnumerable<SFPStep> steps = new List<SFPStep>();
        IEnumerable<SFPStep> steps2 = new List<SFPStep>();
        List<Particle> highPtcles = new List<Particle>();
        Random random = new Random();
        LineGraph pGraph, sGraph, pGraph2, sGraph2;

        public DisagreementGraph(System.Windows.Forms.Screen screen)
        {
            InitializeComponent();
            this.Show();
            this.WindowState = System.Windows.WindowState.Normal;
            this.Left = screen.Bounds.Left;
            this.Top = screen.Bounds.Top;
            this.WindowState = System.Windows.WindowState.Maximized;
        }
		
        Func<Point, double> mapping = delegate(Point p) { return p.X; };
        Func<Point, double> pMapping = delegate(Point p) { return p.Y; };  
		
		public void createDisagreementGraph(List<Point> stepData, List<Point> particleData, System.IO.FileInfo srcFile){
            string adder = "";
            LineGraph pargraph;
            LineGraph solgraph;
            if (srcFile.Name.Contains("Combine"))
                adder = "Bayes ";
            else if (srcFile.Name.Contains("Separate"))
                adder = "Non-Bayes ";
            pargraph = Disagreement.AddLineGraph(new EnumerableDataSource<Point>(particleData) { XMapping = mapping, YMapping = pMapping }, new Pen(GetRandomBrush(), 1), new PenDescription(adder + "Raw Data"));
            solgraph = Disagreement.AddLineGraph(new EnumerableDataSource<Point>(stepData) { XMapping = mapping, YMapping = pMapping }, new Pen(GetRandomBrush(), 1), new PenDescription(adder + "Solution Data"));
            if (srcFile.Name.Contains("Combine")) {
                pGraph = pargraph;
                sGraph = solgraph;
            }
            else {
                pGraph2 = pargraph;
                sGraph2 = solgraph;
            }
		}

		private System.Windows.Media.Brush GetRandomBrush(){
            SolidColorBrush brush = new SolidColorBrush();
            double r, g, b;
            double lightness = random.NextDouble()*0.5 + 0.4; // not too dark nor too light
            double hue = random.NextDouble() * 360.0; // full hue spectrum
            double saturation = random.NextDouble()*0.8 + 0.2; // not too grayish
            ColorTransform transform = new ColorTransform();
            transform.HSLtoRGB(hue, saturation, lightness, out r, out g, out b);
            brush.Color = System.Windows.Media.Color.FromRgb((byte)(r * 255.0), (byte)(g * 255.0), (byte)(b * 255.0));
            return brush;
        }

        private static double StandardDeviation(double[] data)
        {
            double ret = 0;
            double DataAverage = 0;
            double TotalVariance = 0;
            int Max = 0;
            try{
                Max = data.Length;
                if (Max == 0) { return ret; }
                DataAverage = Average(data);
                for (int i = 0; i < Max; i++)
                    TotalVariance += Math.Pow(data[i] - DataAverage, 2);
                ret = Math.Sqrt(SafeDivide(TotalVariance, Max));
            }
            catch (Exception) { throw; }
            return ret;
        }

        private static double Average(double[] data)
        {
            double DataTotal = 0;
            try
            {
                for (int i = 0; i < data.Length; i++)
                    DataTotal += data[i];
                return SafeDivide(DataTotal, data.Length);
            }
            catch (Exception) { throw; }
        }

        private static double SafeDivide(double value1, double value2)
        {
            double ret = 0;
            try{
                if ((value1 == 0) || (value2 == 0)) { return ret; }
                ret = value1 / value2;
            }
            catch { }
            return ret;
        }

        private void solutionsCheck(object sender, System.Windows.RoutedEventArgs e)
        {
            int sIndex = 0, sIndex2 = 0;
            foreach (object item in Disagreement.Children){
                try {
                    if (((LineGraph)item).Equals(sGraph))
                        sIndex = Disagreement.Children.IndexOf((IPlotterElement)item);
                    else if (((LineGraph)item).Equals(sGraph2))
                        sIndex2 = Disagreement.Children.IndexOf((IPlotterElement)item);
                }
                catch (Exception err) { }
            }
            try {
                if ((bool)((CheckBox)sender).IsChecked) {
                    ((LineGraph)Disagreement.Children[sIndex]).Visibility = Visibility.Visible;
                    ((LineGraph)Disagreement.Children[sIndex2]).Visibility = Visibility.Visible;
                }
                else {
                    ((LineGraph)Disagreement.Children[sIndex]).Visibility = Visibility.Hidden;
                    ((LineGraph)Disagreement.Children[sIndex2]).Visibility = Visibility.Hidden;
                }
            }
            catch (Exception err) { }
        }
        
        private void rawDataCheck(object sender, System.Windows.RoutedEventArgs e)
        {
            int pIndex = 0, pIndex2 = 0;
            foreach (object item in Disagreement.Children) {
                try {
                    if (((LineGraph)item).Equals(pGraph))
                        pIndex = Disagreement.Children.IndexOf((IPlotterElement)item);
                    else if (((LineGraph)item).Equals(pGraph2))
                        pIndex2 = Disagreement.Children.IndexOf((IPlotterElement)item);
                }
                catch (Exception err) { }
            }
            try {
                if ((bool)((CheckBox)sender).IsChecked) {
                    ((LineGraph)Disagreement.Children[pIndex]).Visibility = Visibility.Visible;
                    ((LineGraph)Disagreement.Children[pIndex2]).Visibility = Visibility.Visible;
                }
                else {
                    ((LineGraph)Disagreement.Children[pIndex]).Visibility = Visibility.Hidden;
                    ((LineGraph)Disagreement.Children[pIndex2]).Visibility = Visibility.Hidden;
                }
            }
            catch (Exception err) { }
        }

        private void bayesCheck(object sender, System.Windows.RoutedEventArgs e)
        {
        	int pIndex = 0, pIndex2 = 0;
            foreach (object item in Disagreement.Children) {
                try {
                    if (((LineGraph)item).Equals(sGraph))
                        pIndex = Disagreement.Children.IndexOf((IPlotterElement)item);
                    else if (((LineGraph)item).Equals(pGraph))
                        pIndex2 = Disagreement.Children.IndexOf((IPlotterElement)item);
                }
                catch (Exception err) { }
            }
            try {
                if ((bool)((CheckBox)sender).IsChecked) {
                    ((LineGraph)Disagreement.Children[pIndex]).Visibility = Visibility.Visible;
                    ((LineGraph)Disagreement.Children[pIndex2]).Visibility = Visibility.Visible;
                }
                else {
                    ((LineGraph)Disagreement.Children[pIndex]).Visibility = Visibility.Hidden;
                    ((LineGraph)Disagreement.Children[pIndex2]).Visibility = Visibility.Hidden;
                }
            }
            catch (Exception err) { }
        }

        private void nonBayesCheck(object sender, System.Windows.RoutedEventArgs e)
        {
        	int pIndex = 0, pIndex2 = 0;
            foreach (object item in Disagreement.Children) {
                try {
                    if (((LineGraph)item).Equals(sGraph2))
                        pIndex = Disagreement.Children.IndexOf((IPlotterElement)item);
                    else if (((LineGraph)item).Equals(pGraph2))
                        pIndex2 = Disagreement.Children.IndexOf((IPlotterElement)item);
                }
                catch (Exception err) { }
            }
            try {
                if ((bool)((CheckBox)sender).IsChecked) {
                    ((LineGraph)Disagreement.Children[pIndex]).Visibility = Visibility.Visible;
                    ((LineGraph)Disagreement.Children[pIndex2]).Visibility = Visibility.Visible;
                }
                else {
                    ((LineGraph)Disagreement.Children[pIndex]).Visibility = Visibility.Hidden;
                    ((LineGraph)Disagreement.Children[pIndex2]).Visibility = Visibility.Hidden;
                }
            }
            catch (Exception err) { }
        }
    }
	
	public class ColorTransform
    {
        public void HSLtoRGB(double hue, double saturation, double luminance, out double red, out double green, out double blue)
        {
            double q;
            double p;
            if (luminance < 0.5)
                q = luminance * (1.0 + saturation);
            else
                q = luminance + saturation - (luminance * saturation);
            p = 2 * luminance - q;
            double hk = hue / 360.0;
            double tr = hk + 1.0 / 3.0;
            double tg = hk;
            double tb = hk - 1.0 / 3.0;
            tr = Normalize(tr);
            tg = Normalize(tg);
            tb = Normalize(tb);
            red = ComputeColor(q, p, tr);
            green = ComputeColor(q, p, tg);
            blue = ComputeColor(q, p, tb);
        }

        private double ComputeColor(double q, double p, double tc)
        {
            if (tc < 1.0 / 6.0)
                return p + ((q - p) * 6.0 * tc);
            if (tc < 0.5)
                return q;
            if (tc < 2.0 / 3.0)
                return p + ((q - p) * 6.0 * (2.0 / 3.0 - tc));
            return p;
        }

        private static double Normalize(double tr)
        {
            if (tr < 0)
                return tr + 1.0;
            if (tr > 1.0)
                return tr - 1.0;
            return tr;
        }
    }
}
